package com.guiji.text2video.job.task;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HtmlUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.guiji.text2video.common.redis.service.RedisService;
import com.guiji.text2video.job.domain.WavBO;
import com.guiji.text2video.job.mapper.Text2videoJobMapper;
import com.guiji.text2video.job.util.DouyinHuman;
import com.guiji.text2video.job.util.GeneratID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @Copyright (C), 2018-2021
 * @FileName: DouyinSubmit
 * @Author: scl
 * @Date: 2021/11/3 16:35
 * @Description: 抖音任务提交
 */
@Component("douyin")
public class DouyinSubmit {

    private static final Logger logger = LoggerFactory.getLogger(DouyinSubmit.class);

    @Autowired
    private RedisService redisService;

    @Autowired(required = false)
    Text2videoJobMapper jobMapper;

    @Autowired
    PushTask pushTask;

    @Value("${spring.profiles.active}")
    private String env;

    private static String redisFront = "douyin-";


    /**
     * @descp: 目录和视频类别对应关系
     * @param: 放在redis中，定期更新。
     * @Author: scl
     * @Date: 2021/11/5 15:34
     */
    public void directoryAndCategory() {

        String url = "http://172.16.160.55/douyin/readme.md";
        String path = "/data/hdd/douyin/";
        HttpResponse response = HttpRequest.get(url).execute();
        String resp = response.body();
        resp = HtmlUtil.cleanHtmlTag(resp);

        String lines[] = resp.split("\\r?\\n");
        for (String line : lines) {
            if (line.contains(path)) {
                String directory = line.split("\t")[0].split(" ")[0];
                String key = directory.replace(path, "");
                logger.info("存入key:value值：{}", key + ":" + line);
                redisService.setCacheObject(key, line);
            }
        }
    }


    /**
     * @descp: 将目录下所有文件视频，进行提交任务到redis中
     * @param: 字符串，目录名称
     * 'yejy'
     *
     * 'kjdbh'
     * @Author: scl
     * @Date: 2021/11/3 17:11
     */
    public void submit(String direction) {

        String url = "http://172.16.160.55/douyin/";
        String douyin = url + direction + "/";
        logger.info("加载目录：{}", douyin);

        List<String> videoList = new ArrayList<String>();
        HttpResponse douResponse = HttpRequest.get(douyin).execute();
        String dResponse = douResponse.body();
        dResponse = HtmlUtil.cleanHtmlTag(dResponse);
        String dlines[] = dResponse.split("\\r?\\n");
        for (String line : dlines) {
            if (line.contains(".mp4")) {//筛选视频
                String fileName = line.split(".mp4")[0] + ".mp4";
                String cacheUrl = douyin + fileName;
                videoList.add(cacheUrl);
                redisService.setCacheObject(redisFront + direction + System.currentTimeMillis() + RandomUtil.randomInt(100, 200), cacheUrl);
            }
        }
        logger.info("加载目录：{},缓存大小：{}", douyin, videoList.size());
    }

    /**
     * @descp: 放入缓存，解耦：如果合成出错可以放回重试。不同的二创类型使用，不同缓存key。
     * （目录,3）：表示科技视频合成3个视频。
     * （目录,3）：表示育儿视频合成3个视频。
     *
     *
     * 用目录做分区视频类别：
     * 'yejy',2
     *
     *
     *
     * @param: 每天次提交任务数量
     * @Author: scl
     * @Date: 2021/11/3 17:11
     */
    public void execute(String direction, Integer size) {

        Collection<String> collections = redisService.keys(redisFront + direction + "*");

        logger.info("缓存抖音任务目录:{},任务数:{}", redisFront + direction, collections.size());
        if (collections.size() == 0) {
            return;
        }

        //根据目录确定视频类别，确定使用的数字人，确定切割参数。
        if (ObjectUtil.isEmpty(redisService.getCacheObject(direction))) {
            logger.info("参数direction找不到缓存，任务终止:{}", direction);
            return;
        }
        //每次执行size个任务。
        List<String> videoList = new ArrayList<String>();
        int count = 0;
        for (String key : collections) {
            if (count == size) {
                break;
            }
            videoList.add(redisService.getCacheObject(key));
            redisService.deleteObject(key);
            count++;
        }

        //开始执行
        String wavUrl = "http://172.16.160.53:20001/call/364";
        String segmentVideoUrl = "http://172.16.160.53:20001/call/365";
        //带数字人,偶数是52节点合成，奇数是51节点。将0-8点钟任务负载分开。
        String composeVideoUrl = "http://172.16.160.52:20001/call/360";
        if (size % 2 == 1) {
            composeVideoUrl = "http://172.16.160.51:20001/call/360";
        }

        String cachePath = "/data/hdd/secondcreation/cache/";
        String videoPath = "/data/hdd/secondcreation/video/";

        String nginxFront = "http://172.16.160.54/secondcreation/";

        String videoSpilteParam = "";
        String videoComposeParam = "";

        //循环提交任务
        for (String videoUrl : videoList) {

            //时间戳生成id
            String name = GeneratID.getJobGeneratDouYinID();
            //根据目录确定视频类别，确定使用的数字人，确定切割参数。
            String line = redisService.getCacheObject(direction);
            if (line.contains("育儿")) {
                videoSpilteParam = DouyinHuman.getYuErSplitVideo(videoUrl);
                videoComposeParam = DouyinHuman.getYanshuhanYuEr(nginxFront, name);
            } else if (line.contains("科技")) {
                videoSpilteParam = DouyinHuman.getKejiSplitVideo(videoUrl);
                videoComposeParam = DouyinHuman.getKeji(nginxFront, name);
            } else {
                logger.info("for判断不了视频类型，跳过本次任务");
                continue;
            }

            //1,音频请求
            HttpResponse httpResponse = null;
            WavBO wav = new WavBO();
            wav.setPath(videoUrl);
            try {
                httpResponse = HttpRequest.post(wavUrl).timeout(360000).body(JSONUtil.parseObj(wav).toString()).executeAsync();
            } catch (Exception e) {
                logger.info("音频链接拒绝");
            }

            if (ObjectUtil.isNotEmpty(httpResponse) && httpResponse.getStatus() == 200) {
                BufferedOutputStream outputStream = FileUtil.getOutputStream(cachePath + name + ".wav");
                httpResponse.writeBody(outputStream, true, null);
            } else {
                logger.info("音频请求-失败：{},原因：{}", videoUrl, httpResponse.body());
                redisService.setCacheObject(redisFront + System.currentTimeMillis(), videoUrl);
                continue;
            }

            //2,切割视频请求
            HttpResponse videoResponse = null;

            try {
                videoResponse = HttpRequest.post(segmentVideoUrl).timeout(360000).body(JSONUtil.parseObj(videoSpilteParam).toString()).executeAsync();
            } catch (Exception e) {
                logger.info("视频切分链接拒绝");
            }

            if (ObjectUtil.isNotEmpty(videoResponse) && videoResponse.getStatus() == 200) {
                BufferedOutputStream outputStream = FileUtil.getOutputStream(cachePath + name + ".mp4");
                videoResponse.writeBody(outputStream, true, null);
            } else {
                logger.info("切割视频请求-失败：{},原因：{}", videoUrl, videoResponse.body());
                redisService.setCacheObject(redisFront + System.currentTimeMillis(), videoUrl);
                continue;
            }

            if ("dev".equals(env)) {
                logger.info("开发环境,请求参数：{}", videoComposeParam);
            }

            //3,合成视频
            HttpResponse response = null;
            String chineseName = FileNameUtil.getName(URLUtil.decode(videoUrl));
            String subName = URLUtil.decode(videoUrl).replace(chineseName, "");
            String erName = FileNameUtil.getName(subName);

            try {
                response = HttpRequest.post(composeVideoUrl).timeout(360000).body(videoComposeParam).executeAsync();
            } catch (Exception e) {
                logger.info("视频合成链接拒绝");
            }

            String saveLocation = videoPath + erName + "/" + chineseName;
            if (ObjectUtil.isNotEmpty(response) && response.getStatus() == 200) {

                BufferedOutputStream outputStream = FileUtil.getOutputStream(saveLocation);
                response.writeBody(outputStream, true, null);

                logger.info("抖音二创视频-成功：{}", nginxFront + "video/" + erName + "/" + chineseName);
            } else {
                logger.info("抖音二创视频-失败：{},原因：{}", videoUrl, response.body());
                redisService.setCacheObject(redisFront + System.currentTimeMillis(), videoUrl);
            }

            if ("dev".equals(env)) {
                logger.info("开发环境，不清空音频和剪辑视频");
            } else {

                //Linux命令写法   .sh文件之后可以再加命令getModuleList
                String deleteCache = "rm -f " + cachePath + name + ".wav" + "  " + cachePath + name + ".mp4 "+saveLocation;
                String[] delete = {"/bin/sh", "-c", deleteCache};
                //视频写回55节点
                String writeToNginx = "sshpass -p Guiji2021go! scp " + saveLocation + " root@172.16.160.55:/data/hdd/douyin/" + erName + "-scp";
                String[] wcommand = {"/bin/sh", "-c", writeToNginx};
                try {
                    //Runtime.getRuntime().exec本身是一个异步方法，通过Helpers.asynchOutputWrite生成了一个新线程。所以等待上步执行完，再删除。
                    Runtime.getRuntime().exec(wcommand);
                    Thread.sleep(10000);
                    Runtime.getRuntime().exec(delete);
                    logger.info("执行写回:{}", writeToNginx);
                } catch (IOException e) {
                    logger.info("二创清空音频和剪辑视频:执行异常");
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }


}